package br.unesp.demac.bcc.soo.clarus.dao;

import br.unesp.demac.bcc.soo.clarus.bean.Autor;
import br.unesp.demac.bcc.soo.clarus.bean.Editora;
import br.unesp.demac.bcc.soo.clarus.bean.Localizacao;
import br.unesp.demac.bcc.soo.clarus.bean.Obra;
import br.unesp.demac.bcc.soo.clarus.util.FabricaConexao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Evaldo
 */
public class ObraDAOImp implements ObraDAO {
    
    /**
     * Salva dados da obra em inclusão
     * @param obra Obra a ser inserida
     * @return Status da inserção
     * @throws SQLException Exceção SQL
     */
    @Override
    public boolean salvarObra(Obra obra) throws SQLException{
        boolean salvo = false;
        int idEditora = 0;
        int idObra = 0;

        final String query = "INSERT INTO OBRA (nomeObra, anoPublicacao, dataInclusao, flagExcluido, idLocalizacao, idEditora)" +
                " VALUES (?, ?, sysdate(), ?, ?, ?)";
        Connection conn = FabricaConexao.getConexao();
        PreparedStatement pstmt = null;
        ResultSet res = null;

        if (conn != null){
            try{
                conn.setAutoCommit(false);

                //insere a editora
                EditoraDAO editoraDao = new EditoraDAOImp();
                idEditora = editoraDao.salvarEditora(conn, obra.getEditora());

                //insere a obra
                pstmt = conn.prepareStatement(query, PreparedStatement.RETURN_GENERATED_KEYS);
                pstmt.setString(1, obra.getNomeObra());
                pstmt.setInt(2, obra.getAnoPublicacao());
                pstmt.setBoolean(3, false);
                pstmt.setInt(4, obra.getLocalizacao().getIdLocalizacao());
                pstmt.setInt(5, idEditora);
                pstmt.executeUpdate();
                res = pstmt.getGeneratedKeys();
                if (res.next())
                    idObra = res.getInt(1);

                //insere os autores
                AutorDAO autDao = new AutorDAOImp();
                for (Autor aut : obra.getAutor()){
                    autDao.salvarAutor(conn, aut, idObra);
                }

                conn.commit();
                salvo = true;
            }
            catch(SQLException ex){
                System.out.println("Erro ao salvar obra: " + ex.getMessage());
                throw ex;
            }
            finally{
                FabricaConexao.fechar(conn, pstmt);
            }
        }

        return salvo;
    }
    
    /**
     * Atualiza dados de uma obra
     * @param obra Obra a ser atualizada
     * @return Status da atualização
     */
    @Override
    public boolean atualizarObra(Obra obra){
        boolean atualizado = false;
        final String query = "UPDATE OBRA" +
                " SET flagExcluido = ?, idLocalizacao = ? WHERE idObra = ?;";
        Connection conn = FabricaConexao.getConexao();
        PreparedStatement pstmt = null;
        
        if (conn != null){
            try{
                conn.setAutoCommit(false);
                
                //atualizando dados de obra
                pstmt = conn.prepareStatement(query);
                pstmt.setBoolean(1, obra.isFlagExcluido());
                pstmt.setInt(2, obra.getLocalizacao().getIdLocalizacao());
                pstmt.setInt(3, obra.getIdObra());
                pstmt.executeUpdate();
                
                conn.commit();
                atualizado = true;
            }
            catch(SQLException ex){
                System.out.println("Erro ao atualizar obra: " + ex.getMessage());
            }
            finally{
                FabricaConexao.fechar(conn, pstmt);
            }
        }
        
        return atualizado;
    }
    
    @Override
    public Obra getObraById(int idObra) {

        final String query = "SELECT idObra, nomeObra, anoPublicacao, dataInclusao, flagExcluido, idLocalizacao, idEditora "
                + "FROM Obra WHERE idObra = ?";
        Connection conn = FabricaConexao.getConexao();
        PreparedStatement pstmt = null;
        ResultSet res = null;
        Obra obra = null;

        if (conn != null) {
            try {
                
                pstmt = conn.prepareStatement(query);
                pstmt.setInt(1, idObra);
                res = pstmt.executeQuery();

                if (res.next()) {
                    obra = new Obra();
                    obra.setIdObra(res.getInt("idObra"));
                    obra.setNomeObra(res.getString("nomeObra"));
                    obra.setAnoPublicacao(res.getInt("anoPublicacao"));
                    obra.setDataInclusao(res.getDate("dataInclusao"));
                    obra.setFlagExcluido(res.getBoolean("flagExcluido"));
                    
                    AutorDAO adao = new AutorDAOImp();
                    obra.setAutor(adao.getAutoresByObraId(conn, idObra));
                    
                    LocalizacaoDAO ldao = new LocalizacaoDAOImp();
                    obra.setLocalizacao(ldao.getLocalizacaoById(conn, res.getInt("idLocalizacao")));
                    
                    EditoraDAO edao = new EditoraDAOImp();
                    obra.setEditora(edao.getEditoraById(conn, res.getInt("idEditora")));
                    
                    EmprestimoDAO empdao = new EmprestimoDAOImp();
                    obra.setEmprestimo(empdao.getEmprestimoByIdObra(idObra));
                }
                

            } catch (SQLException ex) {
                System.out.println("Erro ao recuperar obra: " + ex.getMessage());
            } finally {
                FabricaConexao.fechar(conn, pstmt);
            }
        }

        return obra;
    }
    
    @Override
    public List<Obra> pesquisarObra(String text) {
        final String query = "SELECT idObra FROM Obra "
                + "JOIN Autor_has_Obra ON idObra = Autor_has_Obra.Obra_idObra "
                + "JOIN Autor ON Autor_has_Obra.Autor_idAutor = Autor.idAutor "
                + "WHERE nomeObra like ? OR nomeAutor like ? "
                + "GROUP BY idObra";
        Connection conn = FabricaConexao.getConexao();
        PreparedStatement pstmt = null;
        ResultSet res = null;
        List<Obra> obras = new ArrayList<Obra>();
        Obra obra = null;
        
        if (conn != null) {
            try {
                
                pstmt = conn.prepareStatement(query);
                pstmt.setString(1, '%'+text+'%');
                pstmt.setString(2, '%'+text+'%');
                res = pstmt.executeQuery();

                while (res.next()) {
                    obra = this.getObraById(res.getInt("idObra"));
                    
                    if (obra != null) {
                        obras.add(obra);
                    }
                }

            } catch (SQLException ex) {
                System.out.println("Erro ao recuperar obra: " + ex.getMessage());
            } finally {
                FabricaConexao.fechar(conn, pstmt);
            }
        }
        
        return obras;
    }
    
    public boolean isDisponivel(Obra obra) {
        boolean disponivel = false;
        final String QUERY = "SELECT count(dataEmprestimo) as emprestimos, count(dataDevolucao) as devolucoes"
                + " FROM Emprestimo WHERE idObra = ?;";
        Connection conn = FabricaConexao.getConexao();
        PreparedStatement pstmt = null;
        ResultSet res = null;
        
        if (conn != null) {
            try {
                
                pstmt = conn.prepareStatement(QUERY);
                pstmt.setInt(1, obra.getIdObra());
                res = pstmt.executeQuery();

                if (res.next()) {
                    disponivel = (res.getInt("emprestimos") == res.getInt("devolucoes")) ? true : false;
                }

            } catch (SQLException ex) {
                System.out.println("Erro ao recuperar obra: " + ex.getMessage());
            } finally {
                FabricaConexao.fechar(conn, pstmt);
            }
        }
        
        return disponivel;
    }
    
    /**
     * Busca a lista de obras cadastradas em cjto com a localização
     * @param nomeObra Nome da obra a ser pesquisada
     * @return Lista de Obras
     * @throws SQLException Exceção SQL
     */
    @Override
    public List<Obra> buscarObrasLocalizacao(String nomeObra) throws SQLException{
        final String query = "SELECT idObra, nomeObra, anoPublicacao, dataInclusao, flagExcluido, ob.idLocalizacao, lo.codigoCorredor, lo.codigoPrateleira, idEditora " +  
            "FROM obra ob JOIN localizacao lo ON ob.idLocalizacao = lo.idLocalizacao " + 
            "WHERE flagExcluido = false AND nomeObra like ? OR ? IS NULL " +
            "ORDER BY nomeObra;";
        
        List<Obra> lstObra = new ArrayList<Obra>();
        Obra obr = null;
        Connection conn = FabricaConexao.getConexao();
        PreparedStatement pstmt = null;
        ResultSet res = null;
        
        if (conn != null){
            try{
                pstmt = conn.prepareStatement(query);
                pstmt.setString(1, '%' + nomeObra + '%');
                pstmt.setString(2, nomeObra);
                res = pstmt.executeQuery();
                
                while (res.next()){
                    obr = new Obra();
                    Localizacao loc = new Localizacao();
                    Editora edit = new Editora();
                    
                    obr.setIdObra(res.getInt(1));
                    obr.setNomeObra(res.getString(2));
                    obr.setAnoPublicacao(res.getInt(3));
                    obr.setDataInclusao(res.getDate(4));
                    obr.setFlagExcluido(res.getBoolean(5));
                    loc.setIdLocalizacao(res.getInt(6));
                    loc.setCodigoCorredor(res.getString(7));
                    loc.setCodigoPrateleira(res.getString(8));
                    obr.setLocalizacao(loc);
                    edit.setIdEditora(res.getInt(9));
                    obr.setEditora(edit);
                    
                    lstObra.add(obr);
                }
            }
            catch(SQLException ex){
                System.out.println("Erro ao consultar obra: " + ex.getMessage());
                throw ex;
            }
            finally{
                FabricaConexao.fechar(conn, pstmt);
            }
        }
        
        return lstObra;
    }
}
